﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Kugar.Core.BaseStruct;
using Kugar.Core.Configuration;
using Kugar.Core.ExtMethod;
using Kugar.Core.Log;
using Kugar.Core.Web;
using Kugar.UI.Web.AdminLTE.Filters;
using Kugar.UI.Web.AdminLTE.Helpers;
using Kugar.UI.Web.AdminLTE.Interfaces;
using Kugar.UI.Web.AdminLTE.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Kugar.UI.Web.AdminLTE.Controllers
{
    //[Area("AdminCore")]
    public class AdminLoginController:WebUIBaseController
    {
        //private IAdminLoginManager _loginManager = null;
        private IAdminManager _adminManager = null;
        private static string _mainTitle = "";
        private static string _subTitle = "";
        private static string _logoUrl = "";
        private static int _viewType = 0;

        static AdminLoginController()
        {
            //var configuration = new ConfigurationBuilder()
            //    .SetBasePath(Directory.GetCurrentDirectory())
            //    .AddJsonFile("appsettings.json")
            //    .Build();

            //_payAppID = configuration["WechatPay:AppID"];// CustomConfigManager.Default.AppSettings.GetValueByName("Pay_AppID");

            _logoUrl= CustomConfigManager.Default["AdminLTE:LogoUrl"];//.IfEmptyOrWhileSpace($"{AdminLTEUI.LayoutPath.ResourceBaseUrl}/Content/images/login_logo.png");
            _mainTitle = CustomConfigManager.Default["AdminLTE:LoginTitle"].IfEmptyOrWhileSpace("后台管理系统");// CustomConfigManager.Default.AppSettings.GetValueByName("adminlte:LoginTitle");
            _subTitle = CustomConfigManager.Default["AdminLTE:LoginSubTitle"];// CustomConfigManager.Default.AppSettings.GetValueByName("adminlte:LoginSubTitle");
            _viewType = CustomConfigManager.Default["AdminLTE:LoginViewType"].ToInt(0);
        }

        public AdminLoginController( IAdminManager manager=null)
        {
            //_loginManager = loginManager;
            
            _adminManager = manager;
        }

        [HttpGet]
        [AllowAnonymous]
        [Route("AdminCore/Login")]
        [Route("AdminCore/Login/{authenticationType}")]
        public async Task<IActionResult> Login()
        {
            var authenticationType = RouteData.Values.TryGetValue("authenticationType", "default").ToStringEx();

            try
            {
                await HttpContext.SignOutAsync(authenticationType);
            }
            catch (Exception e)
            {
            }
            

            var config = GlobalConfiguration.LoginViewSettings.TryGetValue(authenticationType,null);

            var mainTitle = config?.TryGetValue("MainTitle",null).ToStringEx().IfEmptyOrWhileSpace(_mainTitle) ;
            var subTitle = config?.TryGetValue("SubTitle", null).ToStringEx().IfEmptyOrWhileSpace(_subTitle) ;
            var loginImageUrl= config?.TryGetValue("LogoUrl", null).ToStringEx().IfEmptyOrWhileSpace(_logoUrl) ;
            var registerTitle = config?.TryGetValue("RegisterTitle", null);
            var registerUrl = config?.TryGetValue("RegisterUrl", null);
            var forgetpasswordTitle = config?.TryGetValue("ForgetpasswordTitle", null);
            var forgetpasswordUrl = config?.TryGetValue("ForgetpasswordUrl", null);

            var loginPageManager = (ILoginPageManager)config?.TryGetValue("LoginPageManager",null);
  

            Response.Cookies.Append(AdminAuthorityAttribute.CookieOrHeaderName, "", new CookieOptions() { Expires = DateTimeOffset.Now.AddDays(-5), HttpOnly = false, Secure = false, SameSite = SameSiteMode.None });
            
            return View(AdminLTEUI.LayoutPath.LoginViewPath,new Model_Login()
            {
                Title = mainTitle,
                Subtitle = subTitle,
                LogoImageUrl = loginImageUrl,
                ViewType = string.IsNullOrWhiteSpace(mainTitle) && string.IsNullOrWhiteSpace(subTitle) ? 1 : 0,// _viewType
                RegisterTitle = registerTitle.ToStringEx(),
                RegisterUrl = registerUrl.ToStringEx(),
                ForgetpasswordTitle = forgetpasswordTitle.ToStringEx(),
                ForgetpasswordUrl = forgetpasswordUrl.ToStringEx(),
                SliderImageUrls = loginPageManager?.SliderImages(this, authenticationType)
        });
        }

        [ActionName("Login"),HttpPost]
        [AllowAnonymous]
        [Route("AdminCore/Login")]
        [Route("AdminCore/Login/{authenticationType}")]
        public async Task<IActionResult> LoginPost()
        {
            var backurl = Request.GetString("backurl");

            var username = Request.GetString("UserName");
            var pw = Request.GetString("Password");
            var veriCode = Request.GetString("VerificationCode");
            var authenticationType = RouteData.Values.TryGetValue("authenticationType","default").ToStringEx();

            //await HttpContext.Session.LoadAsync();
            var scode= HttpContext.Session.GetString("VerificationCode");

            var config = GlobalConfiguration.LoginViewSettings.TryGetValue(authenticationType, null);

            if (config==null)
            {
                return Content($"未找到{authenticationType}相关配置");
            }

            var mainTitle = config?.TryGetValue("MainTitle", null).ToStringEx().IfEmptyOrWhileSpace(_mainTitle);
            var subTitle = config?.TryGetValue("SubTitle", null).ToStringEx().IfEmptyOrWhileSpace(_subTitle);
            var loginImageUrl = config?.TryGetValue("LogoUrl", null).ToStringEx().IfEmptyOrWhileSpace(_logoUrl);
            var registerTitle = config?.TryGetValue("RegisterTitle", null).ToStringEx();
            var registerUrl = config?.TryGetValue("RegisterUrl", null).ToStringEx();
            var forgetpasswordTitle = config?.TryGetValue("ForgetpasswordTitle", null).ToStringEx();
            var forgetpasswordUrl = config?.TryGetValue("ForgetpasswordUrl", null).ToStringEx();

            var model = new Model_Login()
            {
                Title = mainTitle,
                Subtitle = subTitle,
                LogoImageUrl = loginImageUrl,
                ViewType = string.IsNullOrWhiteSpace(mainTitle) && string.IsNullOrWhiteSpace(subTitle)?1:0,// _viewType
                RegisterTitle = registerTitle.ToStringEx(),
                RegisterUrl = registerUrl.ToStringEx(),
                ForgetpasswordTitle = forgetpasswordTitle.ToStringEx(),
                ForgetpasswordUrl = forgetpasswordUrl.ToStringEx()
            };

            if (!veriCode.CompareTo(scode,true))
            {
                model.Msg = "验证码错误";
            }
            else
            {
                var loginManager = (IAdminLoginManager)config["LoginManager"];

                if (loginManager==null)
                {
                    return Redirect(Request.GetDisplayUrl());
                }

                ResultReturn<string> ret = null;

                try
                {
                    ret = loginManager.Login(username, pw);
                }
                catch (Exception e)
                {
                    LoggerManager.Default.Error("登录接口抛错",e);
                    return Redirect(Request.GetDisplayUrl());
                }
                

                if (ret.IsSuccess)
                {
                    Claim[] claims = null;

                    if (config!=null)
                    {
                        claims=new Claim[]
                        {
                            new Claim("k",pw.DesEncrypt(authenticationType.Trim().ToLower())), 
                            new Claim("UserName",username),
                            new Claim("UserID",ret.ReturnData),
                        };

                        var adminlteIdentity = new ClaimsIdentity(claims, authenticationType);

                        var identityPrincipal = new ClaimsPrincipal(adminlteIdentity);

                        try
                        {
                            await HttpContext.SignInAsync(authenticationType, identityPrincipal, new AuthenticationProperties()
                            {
                                IsPersistent = true,
                                ExpiresUtc = DateTimeOffset.Now.AddDays(5)
                            });
                        }
                        catch (Exception e)
                        {
                            LoggerManager.Default.Error("调用系统登录错误",e);
                            return Redirect(Request.GetDisplayUrl());
                        }
                        

                    }
                    else
                    {
                        var token = BuildToken(userName: username, password: pw);

                        Response.Cookies.Append(AdminAuthorityAttribute.CookieOrHeaderName, token, new CookieOptions() { Expires = DateTimeOffset.Now.AddDays(5), HttpOnly = false, Secure = false, SameSite = SameSiteMode.None });

                    }
                    if (string.IsNullOrWhiteSpace(backurl))
                    {
                        backurl = "/";
                    }
                    return Redirect(backurl);
                }
                else
                {
                    model.Msg = ret.Message;
                }
            }

            model.UserName = username;
            model.Password = pw;

            var loginPageManager = (ILoginPageManager) config?.TryGetValue("LoginPageManager", null);
            model.SliderImageUrls = loginPageManager?.SliderImages(this, authenticationType);

            return View(AdminLTEUI.LayoutPath.LoginViewPath, model);
        }

        [HttpGet]
        [AllowAnonymous]
        [Route("AdminCore/AdminLogin/VerificationCode")]
        public IActionResult VerificationCode()
        {
            var code = RandomEx.NextString(4);
            
            HttpContext.Session.SetString("VerificationCode",code);

            var result = new ValidateCodeResult(code);
            
            return result;
        }

        [HttpGet]
        [AllowAnonymous]
        [Route("AdminCore/AdminLogin/Logout")]
        [Route("AdminCore/AdminLogin/Logout/{authenticationType}")]
        public async Task<IActionResult> Logout()
        {
            var backurl = Request.GetString("backurl");
            var authenticationType = RouteData.Values.TryGetValue("authenticationType", "default").ToStringEx();

            if (string.IsNullOrWhiteSpace(authenticationType))
            {
                Response.Cookies.Append(AdminAuthorityAttribute.CookieOrHeaderName, "", new CookieOptions() { Expires = DateTimeOffset.Now.AddDays(-10) });
            }
            else
            {
                await this.HttpContext.SignOutAsync(authenticationType);
            }

            //var backUrl = Request.GetString("backurl","./");
            var loginUrl = HttpContext.User.FindFirst("LoginUrl")?.Value.ToStringEx("/AdminCore/Login");

            try
            {
                await HttpContext.SignOutAsync(authenticationType);
            }
            catch (Exception e)
            {
            }
            

            return Redirect($"{loginUrl}?backurl=" + HttpUtility.UrlEncode(backurl));
        }

        [HttpGet]
        [Route("AdminCore/AdminLogin/AdminList")]
        public IActionResult AdminList()
        {
            var pageIndex = Request.GetInt("PageIndex",1);
            var keyword = Request.GetString("Keyword");
            var state = Request.GetInt("State", -1);
            var isIFrame = Request.GetBool("isIFrame", false);

            var data = _adminManager.GetAdminList(keyword, state, pageIndex, 20);
            
            var model=new Model_AdminList()
                      {
                          Keyword = keyword,
                          List = data,
                          SelectedState = state,
                          IsIFrame = isIFrame
            };

            return View("~/Views/AdminList.cshtml", model);
        }

        [HttpGet]
        [Route("AdminCore/AdminLogin/AdminDetail")]
        public IActionResult AdminDetail()
        {
            var userID = Request.GetString("UserID");

            Model_AdminInfo model =null;

            if (string.IsNullOrWhiteSpace(userID))
            {
                model=new Model_AdminInfo();
            }
            else
            {
                model = _adminManager.GetAdminByID(userID);

                if (model==null)
                {
                    return NotFound();
                }
            }
            
            return View("~/Views/AdminDetail.cshtml",model);
        }

        [HttpPost,ActionName("AdminDetail")]
        [Route("AdminCore/AdminLogin/AdminDetail")]
        public IActionResult AdminDetailPost()
        {
            var userID = Request.GetString("UserID");
            var userName = Request.GetString("UserName");
            var password = Request.GetString("Password");
            var state = Request.GetInt("State", 0);

            if (string.IsNullOrEmpty(userID))
            {
                if (string.IsNullOrWhiteSpace(userName))
                {
                    ModelState.AddModelError("UserName", "账号不能为空");
                }

                if (string.IsNullOrWhiteSpace(password))
                {
                    ModelState.AddModelError("Password", "密码不能为空");
                }
            }

            Model_AdminInfo model = null;

            if (ModelState.IsValid)
            {
                if (string.IsNullOrWhiteSpace(userID))
                {
                    var ret = _adminManager.AddAdmin(userName, password, state);

                    if (ret.IsSuccess)
                    {
                        MsgBoxAndCloseModal("添加成功",true);
                        model = _adminManager.GetAdminByID(ret.ReturnData);
                    }
                    else
                    {
                        MsgBox(ret.Message);
                    }
                }
                else
                {
                    var ret = _adminManager.UpdateAdmin(userID, state);

                    if (ret.IsSuccess)
                    {
                        MsgBoxAndCloseModal("更新成功",true);
                        model = _adminManager.GetAdminByID(userID);
                    }
                    else
                    {
                        MsgBox("更新失败:" + ret.Message);
                    }
                }
            }

            if (model==null)
            {
                model=new Model_AdminInfo()
                      {
                          UserID = userID,
                          UserName = userName,
                          State = state,
                          Password = password
                      };
            }


            return View("~/Views/AdminDetail.cshtml",model);
        }

        [HttpGet]
       // [AdminAuthority]
        [Route("AdminCore/AdminLogin/ChangePassword")]
        public IActionResult ChangePassword()
        {
            return View("~/Views/AdminChangePassword.cshtml");
        }

        [HttpPost, ActionName("ChangePassword")]
        [Route("AdminCore/AdminLogin/ChangePassword")]
       // [AdminAuthority]
        public IActionResult ChangePasswordPost()
        {
            var oldPassword = Request.GetString("OldPassword");
            var newPassword = Request.GetString("NewPassword");
            var confirmPassword = Request.GetString("ConfirmPassword");

            if (newPassword!= confirmPassword)
            {
                ModelState.AddModelError("ConfirmPassword", "确认密码和新密码不一致");
            }

            var userID = Request.HttpContext.User.FindFirst("UserID").Value;

            if (ModelState.IsValid)
            {
                var ret=_adminManager.ChangePassword(userID, oldPassword, newPassword);

                if (ret.IsSuccess)
                {
                    MsgBoxAndGoto("修改成功", "/AdminCore/AdminLogin/Login");
                }
                else
                {
                    MsgBox("修改失败:" + ret.Message);
                }
            }
            
            return View("~/Views/AdminChangePassword.cshtml");
        }

        [Route("AdminCore/AdminLogin/AdminMethod")]
        public IActionResult AdminMethod(string methodName)
        {
            var userID = Request.GetString("UserID");

            ResultReturn ret = null;

            switch (methodName)
            {
                case "stop":
                {
                    ret = _adminManager.UpdateAdmin(userID, 99);
                    break;
                }
                case "delete":
                {
                    ret = _adminManager.DeleteAdminByID(userID);
                    break;
                }
                case "start":
                {
                    ret = _adminManager.UpdateAdmin(userID, 0);
                        break;
                }
                case "resetpassword":
                {
                    ret = _adminManager.ResetPassword(userID);
                    break;
                }
            }

            if (ret==null)
            {
                return NotFound();
            }

            return this.NewtonJson(ret);
        }

        private string BuildToken(string userName,string password)
        {
            //jwtKey = jwtKey.PadRight(48, ' ');

            var securityKey = new SymmetricSecurityKey(AdminAuthorityAttribute.JWTKeyHWM256);

            // Also note that securityKey length should be >256b
            // so you have to make sure that your private key has a proper length
            //
            var credentials = new SigningCredentials
                (securityKey, SecurityAlgorithms.HmacSha256Signature);

            //  Finally create a Token
            var header = new JwtHeader(credentials);

            var payload = new JwtPayload
                          {
                              {"key", new JObject()
                                      {
                                          ["u"]=userName,
                                          ["p"]=password
                                      }.ToString().DesEncrypt(AdminAuthorityAttribute.DesKey)}
                          };

            var secToken = new JwtSecurityToken(header, payload);
            var handler = new JwtSecurityTokenHandler();

            // Token to String so you can use it in your client
            var tokenString = handler.WriteToken(secToken);

            return tokenString;
        }
    }
}

